<!DOCTYPE html>

<html lang="en" data-content_root="../../">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Threading model &#8212; Pytch  documentation</title>
    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=03e43079" />
    <link rel="stylesheet" type="text/css" href="../../_static/classic.css?v=36340f97" />
    <link rel="stylesheet" type="text/css" href="../../_static/css/pytch-classic.css?v=0321735e" />
    
    <script src="../../_static/documentation_options.js?v=7f41d439"></script>
    <script src="../../_static/doctools.js?v=9bcbadda"></script>
    <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
    
    <link rel="icon" href="../../_static/favicon.ico"/>
    <link rel="author" title="About these documents" href="../../about.html" />
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Hat blocks" href="hat-blocks.html" />
    <link rel="prev" title="Actor-class registration" href="actor-registration.html" /> 
  </head><body>
<div class="NavBar">
  <a href="../../../app/"><h1>Pytch</h1></a>
  <ul>
    <a href="https://pytch.scss.tcd.ie/"><li>About Pytch</li></a>
    <a href="../../index.html"><li>Help</li></a>
    <a href="../../../app/tutorials/"><li>Tutorials</li></a>
    <a href="../../../app/my-projects/"><li>My projects</li></a>
  </ul>
</div>
<div class="warning-work-in-progress">
  <p>These help pages are incomplete — we are working on it!</p>
</div>
  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <section id="threading-model">
<span id="id1"></span><h1>Threading model<a class="headerlink" href="#threading-model" title="Link to this heading">¶</a></h1>
<p>The threading model is fundamentally cooperative rather than
pre-emptive. The Skulpt compiler has been modified to automatically
insert ‘cede control’ calls in the bodies of ‘for’ and ‘while’ loops.
This is a pragmatic approach, and gives behaviour close to Scratch’s:
people are used to saying <code class="docutils literal notranslate"><span class="pre">forever:</span> <span class="pre">…</span></code>, and so we wanted the Python
equivalent <code class="docutils literal notranslate"><span class="pre">while</span> <span class="pre">True:</span> <span class="pre">…</span></code> to behave similarly.</p>
<section id="thread-groups">
<h2>Thread groups<a class="headerlink" href="#thread-groups" title="Link to this heading">¶</a></h2>
<p>The entire set of threads is held in a collection of ‘thread groups’.
Each one contains one or more threads. Each thread is in a particular
state, such as running, or sleeping while waiting to be woken by some
external condition.</p>
<p>The primary motivation for collecting threads into groups was to ease
the implementation of the Scratch-like ‘broadcast and wait’ mechanism,
whereby the thread performing the broadcast then sleeps until all
threads created in response to that broadcast have run to completion.</p>
</section>
<section id="automatically-inserted-cede-control-points">
<h2>Automatically-inserted cede-control points<a class="headerlink" href="#automatically-inserted-cede-control-points" title="Link to this heading">¶</a></h2>
<p>To give semi-automatic ceding of control, in support of familiar Scratch
idioms like <code class="docutils literal notranslate"><span class="pre">forever:</span> <span class="pre">do-once-per-frame-stuff</span></code>, we want to have the
Skulpt compiler insert ‘yield-until-next-frame’ (‘YNF’) calls into loop
bodies, but only for ‘Pytch programs’. A ‘Pytch program’ is detected by
the presence of an <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">pytch</span></code> statement; after seeing such an
import, all for and while loops have YNF calls inserted as the first
statement of their bodies.  The effect of this is that there is a yield
point <em>before</em> each run of a loop body.  Inserting the YNF call at the
end of the loop body would have the undesired effect that <code class="docutils literal notranslate"><span class="pre">continue</span></code>
statements would bypass the yield.</p>
<p>Sometimes the user has a legitimate need for a loop to run ‘all at
once’, such as when checking a list of conditions without updating the
Sprite’s state.  Pytch provides a context manager which lets multiple
loop iterations run in one frame; see <code class="docutils literal notranslate"><span class="pre">LoopIterationsPerFrame</span></code> and
the decorator <code class="docutils literal notranslate"><span class="pre">non_yielding_loop</span></code>.</p>
<p>There is precedent for this behaviour, whereby a magic import changes
the language’s semantics, in Python’s various
<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__import</span> <span class="pre">something</span></code> mechanisms.</p>
</section>
<section id="time-is-sliced-by-frame">
<h2>Time is sliced by ‘frame’<a class="headerlink" href="#time-is-sliced-by-frame" title="Link to this heading">¶</a></h2>
<p>Every frame, all thread-groups are given the chance to run. A
thread-group has a <code class="docutils literal notranslate"><span class="pre">one_frame()</span></code> method to do this. It returns a list
— which might be empty — of the thread groups which are now live. This
list is found by calling all the thread-group’s contained threads’
<code class="docutils literal notranslate"><span class="pre">one_frame()</span></code> methods, and concatenating the results. E.g., if a
broadcast is sent by a thread, we return a one-element list with the new
thread-group. If the current thread-group has at least one live thread,
then it adds itself to the returned list.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">Project</span></code> then does a similar process for its thread-groups,
collecting a new list of thread-groups ready for the following frame. In
practice, it will very often be the case that the same thread-groups are
in this list across many frames.</p>
<p>One big assumption is that the computations within the running threads
can all complete in under 1/60 second. If this fails to hold, project
rendering will be jittery, and the project’s sense of timing, as shown
in the wait-seconds system call, will be wrong.</p>
<p>A thread becomes a zombie once it runs to completion at the Python
level. Or if it’s running on an object which ceases to be a registered
Pytch actor-instance.</p>
</section>
<section id="scheduling">
<h2>Scheduling<a class="headerlink" href="#scheduling" title="Link to this heading">¶</a></h2>
<p>All execution is driven by the <code class="docutils literal notranslate"><span class="pre">one_frame()</span></code> method. Every running
thread gets to resume its suspended execution. There are no guarantees
about which order various threads run in.</p>
</section>
<section id="thread">
<h2>Thread<a class="headerlink" href="#thread" title="Link to this heading">¶</a></h2>
<p>On construction, we run a Python callable, supplying one argument. This
technique is used to run an unbound method, passing a particular
instance as the argument; the effect is <code class="docutils literal notranslate"><span class="pre">obj.method()</span></code>. In fact this
is not quite true: the method call is stored as a pseudo-suspension; see
below.</p>
<p>All threads are running ‘on’ some instance of some actor — this is the
python object passed in on construction of the thread, and the single
argument of the callable.</p>
<p>Threads run until either they complete at the Python level, or they
invoke a Pytch syscall (qv) using the Skulpt suspension mechanism.</p>
<p>The suspension is stored in the <code class="docutils literal notranslate"><span class="pre">Thread</span></code> as <code class="docutils literal notranslate"><span class="pre">skulpt_susp</span></code>. This
process is bootstrapped by duck-typing a suspension whose <code class="docutils literal notranslate"><span class="pre">resume()</span></code>
runs the <code class="docutils literal notranslate"><span class="pre">obj.method()</span></code> call as noted above.</p>
<p>Each frame, the thread gets a chance to run: see ‘Time-slice’ below.</p>
<p>Diagnostics: Each registered instance (<code class="docutils literal notranslate"><span class="pre">PytchActorInstance</span></code>) is given
a global numeric ID. Threads have an info bundle with the instance
they’re running on, state, and, if waiting, a human friendly summary of
what they’re waiting on. Currently unused but could be a ‘top’-style
extra pane next to output/error panes.</p>
<section id="time-slice">
<h3>Time-slice<a class="headerlink" href="#time-slice" title="Link to this heading">¶</a></h3>
<p>Each thread gets a call to its <code class="docutils literal notranslate"><span class="pre">one_frame()</span></code>. That calls into Python
via the <code class="docutils literal notranslate"><span class="pre">resume()</span></code> of its suspension. Three things can happen as a
result:</p>
<ul class="simple">
<li><p>Runs to completion, returning a Python object (usually <code class="docutils literal notranslate"><span class="pre">None</span></code> but
doesn’t have to be). The thread is done; turned into a <code class="docutils literal notranslate"><span class="pre">Zombie</span></code>.</p></li>
<li><p>Calls a Pytch syscall, creating a Skulpt suspension of type
<cite>Pytch</cite>. Handled on the JavaScript side, e.g., broadcast message
will usually create new thread-groups. Most syscalls act as
co-operative yield points.</p></li>
<li><p>Returns a non-Pytch suspension.  E.g., if <code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code> is
called.  This is treated as an error by <code class="docutils literal notranslate"><span class="pre">one_frame()</span></code>.</p></li>
<li><p>Throws a Python exception, which is turned into a JavaScript
exception. Thread is killed and error message reported.</p></li>
</ul>
</section>
</section>
<section id="thread-state">
<h2>Thread state<a class="headerlink" href="#thread-state" title="Link to this heading">¶</a></h2>
<p>A thread is in one of various states:</p>
<dl class="simple">
<dt>Running</dt><dd><p>This thread is ready to be <code class="docutils literal notranslate"><span class="pre">resume()</span></code>’d at next one-frame.</p>
</dd>
<dt>Zombie</dt><dd><p>No further work will be done, but this thread hasn’t been cleaned up
yet (can become zombie either because Python code has run to
completion, i.e., not invoked syscall; or because object it is
running on has become de-registered).</p>
</dd>
<dt>Sleeping</dt><dd><p>The thread is waiting for some condition to become true.  See
<a class="reference internal" href="#types-of-sleep"><span class="std std-ref">Types of sleep</span></a> below.</p>
</dd>
<dt>Raised-Exception</dt><dd><p>The user’s code (or possibly some internal code) raised a Python
exception or threw a JavaScript error during its most recent
scheduled run.  The scheduler (top-level <code class="docutils literal notranslate"><span class="pre">one_frame()</span></code> function)
halts the program if this happens.</p>
</dd>
<dt>Requested-Stop</dt><dd><p>The thread invoked a syscall requesting the program stop.  The
scheduler stops the program if this happens.</p>
</dd>
</dl>
<section id="waking-paused-threads">
<h3>Waking paused threads<a class="headerlink" href="#waking-paused-threads" title="Link to this heading">¶</a></h3>
<p>Thread has <code class="docutils literal notranslate"><span class="pre">maybe_wake()</span></code> and <code class="docutils literal notranslate"><span class="pre">should_wake()</span></code> which test whether the
condition for resumption of that thread has occurred. Done by polling to
avoid callbacks into a project. If the live project changed between
setting up a thread and a completion callback firing, confusion could
result.</p>
</section>
<section id="culling-zombies">
<h3>Culling zombies<a class="headerlink" href="#culling-zombies" title="Link to this heading">¶</a></h3>
<p>The thread-group lets all its threads run, collecting new thread-groups
as noted elsewhere. Some of its threads might have run to completion on
the Python side, i.e., the function / method call returned. Such a
thread becomes a Zombie; the thread-group culls zombies. Doing so might
mean that there are no threads any more; in that case the thread-group
does not include itself in the list of for-next-frame thread groups it
returns.</p>
</section>
<section id="types-of-sleep">
<span id="id2"></span><h3>Types of sleep<a class="headerlink" href="#types-of-sleep" title="Link to this heading">¶</a></h3>
<p>The following kinds of sleeping can happen, caused by the given
user-level calls.</p>
<ul class="simple">
<li><p>Passage of time: <code class="docutils literal notranslate"><span class="pre">wait_seconds()</span></code></p></li>
<li><p>Thread group completion: <code class="docutils literal notranslate"><span class="pre">broadcast_and_wait()</span></code></p></li>
<li><p>Sound completion: <code class="docutils literal notranslate"><span class="pre">play_sound_until_done()</span></code></p></li>
<li><p>Answer to question: <code class="docutils literal notranslate"><span class="pre">ask_and_wait()</span></code></p></li>
</ul>
</section>
</section>
</section>


            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="Main">
        <div class="sphinxsidebarwrapper"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../webapp/user/index.html">Using the Pytch web app</a></li>
<li class="toctree-l1"><a class="reference internal" href="../user/index.html">Writing Pytch programs</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../about.html">About Pytch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../contact.html">Contact</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../../developer.html">Developer documentation</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../../developer/development-setup.html">Development setup</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../developer/design-overview.html">Design overview</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="index.html">VM</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="overview.html">Overview</a></li>
<li class="toctree-l3"><a class="reference internal" href="integration-with-client.html">Integration with client</a></li>
<li class="toctree-l3"><a class="reference internal" href="based-on-skulpt.html">Skulpt: Python / JavaScript bridge</a></li>
<li class="toctree-l3"><a class="reference internal" href="project.html">Project</a></li>
<li class="toctree-l3"><a class="reference internal" href="actor.html">Actor: Sprite and Stage</a></li>
<li class="toctree-l3"><a class="reference internal" href="actor-registration.html">Actor-class registration</a></li>
<li class="toctree-l3 current"><a class="current reference internal" href="#">Threading model</a></li>
<li class="toctree-l3"><a class="reference internal" href="hat-blocks.html">Hat blocks</a></li>
<li class="toctree-l3"><a class="reference internal" href="syscalls.html">Syscalls</a></li>
<li class="toctree-l3"><a class="reference internal" href="skulpt-pytch-environment.html">Skulpt API / Pytch environment</a></li>
<li class="toctree-l3"><a class="reference internal" href="testing.html">Testing</a></li>
<li class="toctree-l3"><a class="reference internal" href="ide-web-app.html">Web-app</a></li>
<li class="toctree-l3"><a class="reference internal" href="rendering.html">Rendering</a></li>
<li class="toctree-l3"><a class="reference internal" href="hit-detection.html">Collision and click detection</a></li>
<li class="toctree-l3"><a class="reference internal" href="clones.html">Clones</a></li>
<li class="toctree-l3"><a class="reference internal" href="sounds.html">Sounds</a></li>
<li class="toctree-l3"><a class="reference internal" href="tutorials.html">Tutorials</a></li>
<li class="toctree-l3"><a class="reference internal" href="docstrings.html">Docstrings</a></li>
<li class="toctree-l3"><a class="reference internal" href="attribute-watchers.html">Watching object attributes</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../webapp/developer/index.html">Webapp</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../medialib/developer/index.html">Media library</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../developer/index.html">Website</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../build-tools/index.html">Tools</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../source-build.html">Source and build information</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../releases/changelog.html">Changelog</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../legal/index.html">Legal information</a></li>
</ul>
<div class="docs-home-link"><hr>
  <ul>
    <li>
      <a href="../../index.html">Pytch help home</a>
    <li>
  </ul>
</div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
  </body>
</html>